// /home/san/src/projects/sanfs/MediaChanger/DataStoreDriver/XmlDataStoreDriver.cs created with MonoDevelop
// User: san at 8:20 PM 5/27/2007
//
// A simple XML based storage backend for the MediaChanger.
// 
//

using System;
using System.Data;
using MySql.Data.MySqlClient;
using System.Xml;
using System.Collections.Generic;
using System.Collections.Specialized;
using SanFS.DiscLibrary;



namespace SanFS.MediaChangerLibrary
{
	public class MySqlDataStoreDriver : IDataStore
	{
		private string	mUri = null;
		IDbConnection dbcon;
		public MySqlDataStoreDriver(string Uri)
		{
			mUri = Uri;
			
			//Console.WriteLine(mUri);
			string[] tokens = Uri.Split(':');
			
			// Assume uri is in format of:
			// ds:MySqlDataStoreDriver:server:db:user:pass			
			string connectionString = String.Format(
          		"Server={0};Database={1};User ID={2};Password={3};Pooling={4}",
          		tokens[2],tokens[3],tokens[4],tokens[5],"false"
          	);
          	       		      
			dbcon = new MySqlConnection(connectionString);
		}
		
		public MySqlDataStoreDriver() {
			//No-op for registering with factory
		}
		public IDataStore CreateInstance(string Uri)
		{
			return new MySqlDataStoreDriver(Uri);
		}
		
		
		public virtual void Initialize()
		{
			
			IDbCommand mDbCommand = dbcon.CreateCommand();
			string sql;
			
			sql = @"DROP TABLE IF EXISTS `sanfs`.`StorageElement`;
					CREATE TABLE  `sanfs`.`StorageElement` (
					  `Slot` int(10) unsigned NOT NULL,
					  `Empty` tinyint(1) NOT NULL,
					  `ElementType` varchar(15) NOT NULL,
					  PRIMARY KEY  (`Slot`)
					) ENGINE=InnoDB DEFAULT CHARSET=latin1;";
					
			mDbCommand.CommandText = sql;
			mDbCommand.ExecuteNonQuery();
			
			sql = @"DROP TABLE IF EXISTS `sanfs`.`Disc`;
					CREATE TABLE  `sanfs`.`Disc` (
					  `Uuid` char(36) NOT NULL,
					  `discId` int(10) unsigned NOT NULL auto_increment,
					  `Type` varchar(10) NOT NULL,
					  `Rewritable` tinyint(1) NOT NULL,
					  `Status` varchar(20) NOT NULL,
					  `TotalSize` bigint(20) unsigned NOT NULL,
					  `FreeSpace` bigint(20) unsigned NOT NULL,
					  `MaxWriteSpeed` int(10) unsigned default NULL,
					  `Version` int(10) unsigned default NULL,
					  PRIMARY KEY  (`discId`)
					) ENGINE=InnoDB DEFAULT CHARSET=latin1;";
					
			mDbCommand.CommandText = sql;
			mDbCommand.ExecuteNonQuery();
			
			sql = @"DROP TABLE IF EXISTS `sanfs`.`DiscFile`;
					CREATE TABLE  `sanfs`.`DiscFile` (
					  `DiscFileId` int(10) unsigned NOT NULL auto_increment,
					  `Uuid` char(36) NOT NULL,
					  `Path` varchar(255) NOT NULL,
					  `TotalSize` bigint(20) unsigned NOT NULL,
					  `TotalChunks` int(10) unsigned NOT NULL,
					  `ChunkNumber` int(10) unsigned NOT NULL,
					  `ChunkSize` bigint(20) unsigned NOT NULL,
					  `ChunkOffset` bigint(20) unsigned NOT NULL,
					  `DiscUuid` char(36) NOT NULL,
					  PRIMARY KEY  (`DiscFileId`)
					) ENGINE=InnoDB DEFAULT CHARSET=latin1;";
					
			mDbCommand.CommandText = sql;
			mDbCommand.ExecuteNonQuery();
			
			

		}
		
		public virtual void SaveDiscList(List<IDisc> Discs)
		{
			Console.WriteLine("Connecting");
			IDbCommand mDbCommand = dbcon.CreateCommand();
			string mSql;			
			
			mSql = @"DELETE FROM DiscFile";
			mDbCommand.CommandText = mSql;
			mDbCommand.ExecuteNonQuery();
			mSql = @"DELETE FROM Disc";
			mDbCommand.CommandText = mSql;
			mDbCommand.ExecuteNonQuery();
			
			foreach(IDisc mDisc in Discs) {
				Console.WriteLine("Inserting disc uuid " + mDisc.Uuid);
				mSql = String.Format(@"INSERT INTO Disc (Uuid, Type,
									Rewritable, Status, TotalSize,
									FreeSpace, MaxWriteSpeed, Version) VALUES
									('{0}', '{1}', {2}, '{3}', {4}, {5}, {6}, {7})",
									mDisc.Uuid, 
									mDisc.Type, 
									mDisc.Rewritable,
									mDisc.Status, 
									mDisc.TotalSize,
									mDisc.FreeSpace, 
									mDisc.MaxWriteSpeed,
									mDisc.Version);
									
				mDbCommand.CommandText = mSql;
				mDbCommand.ExecuteNonQuery();
								
				foreach(IDiscFile mDiscFile in mDisc.Files) {
					mSql = String.Format(@"INSERT INTO DiscFile (Uuid, Path, 
										TotalSize, TotalChunks, ChunkNumber,
										ChunkSize, ChunkOffset, DiscUuid)
										VALUES
										('{0}', '{1}', {2}, {3}, {4}, {5}, {6}, '{7}')",
										mDiscFile.Uuid, 
										mDiscFile.Path,
										mDiscFile.TotalSize, 
										mDiscFile.TotalChunks,
										mDiscFile.ChunkNumber,
										mDiscFile.ChunkSize,
										mDiscFile.ChunkOffset,
										mDisc.Uuid);
										
					mDbCommand.CommandText = mSql;
					mDbCommand.ExecuteNonQuery();
				}
			}
			
		}

		public virtual List<IDisc> GetDiscList()
		{
			List<IDisc> mDiscs = new List<IDisc>();
			Dictionary<Guid,List<IDiscFile>> mDiscFileMap = new Dictionary<Guid,List<IDiscFile>>();
				
			IDbCommand mDbCommand = dbcon.CreateCommand();			
			string mSql;			
								
			mSql = @"SELECT Uuid, Path, TotalSize, TotalChunks, ChunkNumber,
					ChunkSize, ChunkOffset, DiscUuid FROM DiscFile ORDER BY DiscUuid ASC";
									
			mDbCommand.CommandText = mSql;
			Console.WriteLine("Getting DiscFiles");
			IDataReader mReader2 = mDbCommand.ExecuteReader();
			
			while(mReader2.Read()) {
				Console.WriteLine("Getting Guid");
				Console.WriteLine(mReader2.GetString(7));
				Guid mDiscGuid = mReader2.GetGuid(7);
				Console.WriteLine("Creating DiscFile");
				IDiscFile mDiscFile = new DiscFile(
					mReader2.GetGuid(0), // Uuid							
					System.Convert.ToUInt64(mReader2.GetInt64(2)), // TotalSize
					mReader2.GetInt32(3), // TotalChunks
					mReader2.GetString(1), // Path
					mReader2.GetInt32(4), // ChunkNumber
					System.Convert.ToUInt64(mReader2.GetInt64(5)), // ChunkSize
					System.Convert.ToUInt64(mReader2.GetInt64(6)) // ChunkOffset
				);
				if(mDiscFileMap.ContainsKey(mDiscGuid)) {
					mDiscFileMap[mDiscGuid].Add(mDiscFile);												
				}
				else {
					mDiscFileMap.Add(mDiscGuid,new List<IDiscFile>());
					mDiscFileMap[mDiscGuid].Add(mDiscFile);
				}
			}
			
			mReader2.Close();
			mReader2 = null;
				
			mSql = @"SELECT Uuid, Type,	Rewritable, Status, TotalSize,
					FreeSpace, MaxWriteSpeed, Version FROM Disc
					ORDER BY discId ASC";					
			
			mDbCommand.CommandText = mSql;
			IDataReader mReader = mDbCommand.ExecuteReader();
			
			while(mReader.Read()) {
				mDiscs.Add(
					new Disc(
						(EDiscType)Enum.Parse(typeof(EDiscType),mReader.GetString(1)), // Type
						mReader.GetBoolean(2), // Rewritable
						(EDiscStatus)Enum.Parse(typeof(EDiscStatus),mReader.GetString(3)), // Status
						System.Convert.ToUInt64(mReader.GetInt64(4)), // TotalSize
						System.Convert.ToUInt64(mReader.GetInt64(5)), // FreeSpace	
						mReader.GetInt32(6), // MaxWriteSPeed						
						mReader.GetGuid(0), // Uuid
						mReader.GetInt32(7), // Version						
						mDiscFileMap[mReader.GetGuid(0)]));
			}
			
			mReader.Close();
			mReader = null;
			mDbCommand.Dispose();
			mDbCommand = null;
			
			return mDiscs;
		}

		public virtual void SaveStorageElementList(List<IStorageElement> StorageElements)
		{
		#if false
			IDbCommand mDbCommand = dbcon.CreateCommand();
			string mSql;			
				
			mSql = @"DELETE FROM StorageElement";
			mDbCommand.CommandText = mSql;
			mDbCommand.ExecuteNonQuery();
			
			foreach(IStorageElement mStorageElement in StorageElements) {
				mSql = String.Format(@"INSERT INTO StorageElement (Slot,
									Empty, ElementType) VALUES
									({0}, {1}, '{2}')",
									mStorageElement.DeviceSlot,
									mStorageElement.IsEmpty,
									mStorageElement.Type
									);
				//Console.WriteLine(mSql);			
				mDbCommand.CommandText = mSql;
				mDbCommand.ExecuteNonQuery();
			}
		#endif
		}

		public virtual List<IStorageElement> GetStorageElementList()
		{
		    return null;
		#if false
			//Console.WriteLine("Getting elements");
			List<IStorageElement> mStorageElements = 
				new List<IStorageElement>();
				
			IDbCommand mDbCommand = dbcon.CreateCommand();
			string mSql;			
			
			mSql = @"SELECT Slot, Empty, ElementType FROM StorageElement
					ORDER BY Slot ASC";					
			
			mDbCommand.CommandText = mSql;
			IDataReader mReader = mDbCommand.ExecuteReader();
			//Console.WriteLine("Begin loop");
			while(mReader.Read()) {	
			
				//Console.WriteLine("Slot str: " + mReader["Slot"]);
				int mSlot = mReader.GetInt32(0);
				//Console.WriteLine("Slot: " + mSlot);				
				ElementType mType = (ElementType)Enum.Parse(typeof(ElementType),
							mReader.GetString(2));
				//Console.WriteLine("Type: " + mType);
				bool mEmpty = mReader.GetBoolean(1);
				//Console.WriteLine("Empty? " + mEmpty);
				mStorageElements.Add(new StorageElement(mSlot, mType, mEmpty, Guid.Empty));
			}
			
			return mStorageElements;
		#endif
		}

		public virtual void Disconnect()
		{
			dbcon.Close();
			dbcon = null;
		}

		public virtual void Connect()
		{
			dbcon.Open();
		}
		
		public string Uri
		{
			get { return this.mUri; }
		}
		
		public string Key
		{
			get
			{
				return this.GetType().Name;
			}
		}
	} // END CLASS
}  // END NAMESPACE